require 'rextral.rb'

# This file is the implementation of the loading DSL.
#  There are two methods related to 
#   1.  CSV to database load
#   2. database to database load.

class Loading

      class Constraint

            def self.method_missing(method_name,options={})
                  method_name_array = method_name.to_s.split("_")
                  constraint_name = method_name_array[1..(method_name_array.length-2)].join("_")
                  options.each{|key,value|
                          key.each{|inner_key,inner_value|
                            if !inner_value.nil?
                                Constraint.get_columns_list_based_on_constraint(constraint_name,inner_key.to_s,inner_value[0],value)
                            end    
                        }    
                  }    
            end           
                  
                  
            def self.get_columns_list_based_on_constraint(constraint_name,table_name,source_connection,destination_connection)
                  all_columns = source_connection.execute("desc #{table_name}")
                  required_columns = []
                  const_obj = Constraint.new
                  constraint_name = const_obj.get_constraint_name(constraint_name)
                  for column in all_columns
                        if column.include? constraint_name
                              required_columns << column[0]
                        end  
                  end 
                execute_partial_column_loading(required_columns,table_name,source_connection,destination_connection)
            end  
            
          
            def get_constraint_name(constraint_name) 
                  case constraint_name
                        when "not_null"
                              return "NOT NULL"
                        when "primary_key"
                              return "PRI"
                        when "unique"
                              return "UNIQUE"
                        else
                              return "auto_increment"    
                  end
            end 
      end



  def self.load_selected_columns(options={})
        options.each{|key,value|
            # Here key is the hash and value is the destination connection.
            key.each{|inner_key,inner_value|
                # Here inner_key and inner_value are the source tablename and the columns from it.
                        column_list = inner_value - [inner_value[0]]
                        table_name = inner_key.to_s
                        source_connection = inner_value[0]
                        execute_partial_column_loading(column_list,table_name,source_connection,value)
            }
        }
  end
  
  
  
	def self.load load_string
        $load_string = load_string  
        loading_in_progress = Loading.new
        return loading_in_progress
	end	
	
  
  
	def from source_connection
        #~ all_tables = source_connection.query("show tables")
        all_tables = source_connection.tables
        if $load_string.respond_to?"join"
              if $load_string[0].respond_to? "abs"
                    $all_tables = get_columns_from_numbers($load_string,all_tables)
              elsif $load_string[0].respond_to? "split"	
                    $all_tables = get_columns_from_positions($load_string,all_tables)
              end	
        else	
              $all_tables = get_columns_from_positions($load_string,all_tables)
        end
        $source_connection = source_connection
        loading_in_progress_two = Loading.new
        return loading_in_progress_two
	end	
	
  
  
	def to destination_connection
        table_hash = {:table_names=>$all_tables}
        Loading.db_to_db_load($source_connection,destination_connection,table_hash)
	end
	
	
  
  # Here the two connections are the source and destination databases.Here source_connection is optional.
	# The third argument i.e. the block, is file list for loading.
	def self.load_to_database(destination_connection,source_connection,table_hash)
        file_names = table_hash[:table_names]
        if table_hash[:from_file]
              file_names = Loading.all_files_from(table_hash[:table_names])
        else
              file_names = Loading.get_all_file_names(source_connection,file_names)
        end
        for file_name in file_names
              if file_name.to_s.scan("header").size != 0 
                    print "#{file_name} is likely to be a header file."
                    puts
              elsif file_name.to_s.scan("structure").size != 0 	
                    print "#{file_name} is likely to be a structure file."
                    puts
              else
                    execute_loading(file_name.to_s.split("\/").last ,destination_connection)
              end	  
        end	
	end	
	
  def self.get_all_file_names(source_connection,file_name_array)
        file_names = []
        if file_name_array == :all
              #~ all_table_names = source_connection.query("show tables")
              all_table_names = source_connection.tables
              for table_name in all_table_names
                    file_names << table_name.to_s+".csv"
              end	
        else	
              for file_name in file_name_array
                    file_names << file_name.to_s+".csv"
              end
        end	
        return file_names
	end	
	
		
	# This method is for the db_to_db loading.
	# db to db loading is possible only if the destination and the source are different.
	def self.db_to_db_load(source_connection,destination_connection,table_hash)
          if source_connection != destination_connection
                Extraction.extract_to_csv(source_connection,table_hash)
                Loading.load_to_database(destination_connection,source_connection,table_hash)
          end	
	end	



  # This method extracts all the files from the given directory.
	# For this pathname library is being used.
  def self.all_files_from(pathname)
        puts pathname
        new_pathname = Pathname.new(pathname)	
        all_files = new_pathname.children
        file_array = []
        for file in all_files
              file_array << file if file.extname.to_s == ".csv"
        end
        return file_array
	end	
end	